﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Linq.Expressions;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Collections.ObjectModel;
using System.Collections;

namespace NMoq.Core
{
    /// <summary>
    /// The Equal and GetHashCode method had been overrided,
    /// And the Equal method is to compare the MethodMessageInfo instance's Serialize() value
    /// </summary>
    public class MethodMessageInfo  
    {
        #region methodMessage information
        public MethodMessageInfo()
        {
            Args = new object[] { };            
        }

        public MethodInfo MethodInfo
        {
            get;
            set;
        }

        public object[] Args
        {
            get;
            set;
        }

        public object Target
        {
            get;
            set;
        }
        #endregion

        #region  identifier
        public int GetIdentifier<TAction>() where TAction :IAction 
        {
            return  IdentifierFactory.CreateIdentifier<TAction>().GetIdentifier(this);
        }
        #endregion

        #region static methods

        public static MethodMessageInfo CreateMethodMessageInfo(IMethodCallMessage callMessage, object target)
        {
            MethodMessageInfo methodMessageInfo = new MethodMessageInfo()
            {
                Args = callMessage.Args,
                MethodInfo = callMessage.MethodBase as MethodInfo,
                Target = target
            };
            return methodMessageInfo;
        }

        public static MethodMessageInfo CreateMethodMessageInfo<T, TResult>(Expression<Func<T, TResult>> expression, object target)
        {
            MethodCallExpression methodCallExpression = expression.Body as MethodCallExpression;
            MethodMessageInfo methodMessageInfo = new MethodMessageInfo()
            {
                Args = GetArgs(methodCallExpression.Arguments),
                MethodInfo = methodCallExpression.Method,
                Target = target
            };
            return methodMessageInfo;
        }

        public static MethodMessageInfo CreateMethodMessageInfo<T>(Expression<Action<T>> expression, object target)
        {
            MethodCallExpression methodCallExpression = expression.Body as MethodCallExpression;
            MethodMessageInfo methodMessageInfo = new MethodMessageInfo()
            {
                Args = GetArgs(methodCallExpression.Arguments),
                MethodInfo = methodCallExpression.Method,
                Target = target
            };
            return methodMessageInfo;
        }
        public static MethodMessageInfo CreateMethodMessageInfo(Expression<Delegate> expression, object target)
        {
            MethodCallExpression methodCallExpression = expression.Body as MethodCallExpression;
            MethodMessageInfo methodMessageInfo = new MethodMessageInfo()
            {
                Args = GetArgs(methodCallExpression.Arguments),
                MethodInfo = methodCallExpression.Method,
                Target = target
            };
            return methodMessageInfo;
        }

        public static object[] GetArgs(ReadOnlyCollection<Expression> collection)
        {
            ArrayList args = new ArrayList();
            foreach (Expression exp in collection)
            {
                ConstantExpression constant = exp as ConstantExpression;
                if (constant != null)
                    args.Add(constant.Value);
            }
            return args.ToArray();
        }

        public static string ConvertArrayToString(object[] args)
        {
            string result = string.Empty;
            foreach (object arg in args)
            {
                if (arg.GetType() == typeof(Type)
                 || arg.GetType() == typeof(string)
                 || arg.GetType().IsValueType)
                {
                    result += arg.ToString();
                }
                else
                {
                    result += arg.GetHashCode();
                }
            }
            return result;
        }
        #endregion

    }
}
